using System;
using System.Linq;
using T.FAS.Runtime.Base.Entity;
using T.FAS.Runtime.Metadata.Entity.DataModel;
using T.FAS.Runtime.Metadata.Client;
using T.FAS.Runtime.Metadata.SPI;
using T.FAS.Runtime.StateMachine.Service;
using T.FAS.Runtime.DataAccess.SPI;
using T.FAS.Runtime.DataAccess.Service;
using System.Collections.Generic;
using T.ServiceComponent.Kernel.Service;
using Newtonsoft.Json;
using T.FAS.Runtime.DataAccess.Engine;

namespace T.FAS.Runtime.DataAccess.Service
{
    public class DataQueryService 
    {

        private static readonly object s_lockObj = new object();
        private static DataQueryService s_instance = new DataQueryService();
        private readonly IMetaDataClientService metaDataClientService = MetaDataClientService.GetInstance();

        private DataQueryService()
        {

        }

        public static DataQueryService GetInstance()
        {
            if (s_instance == null)
            {
                lock (s_lockObj)
                {
                    s_instance = new DataQueryService();
                }
            }
            return s_instance;
        }


        public string GetDQActionSQL(string dqId)
        {
            DataQuery dq = metaDataClientService.GetMetaData(dqId).Content as DataQuery;
            if (dq == null)
                throw new Exception(string.Format(CommonStringClassService.DataQueryMetaData_GetInstanceFail,dqId));
            var sql = UnifiedDataAccessServiceFactory.GetInstance().GetDQActionSQL(dq);
            return sql;
        }

        public QueryPlan RepairQueryPlan(QueryPlan queryPlan)
        {
            var dqId = queryPlan.DQID;
            DataQuery dataQuery = RTPMetadataHelper.GetRTPMetadata(dqId) as DataQuery;
            if (dataQuery == null)
                throw new Exception(string.Format(CommonStringClassService.DataQueryMetaData_GetInstanceFail, dqId));

            try
            {
                var filterGroup = JsonConvert.DeserializeObject<Group>(queryPlan.FilterContent);
                var colContent = JsonConvert.DeserializeObject<List<QueryPlanColumnContent>>(queryPlan.ColumnContent);
                var sortContent = JsonConvert.DeserializeObject<List<QueryPlanSortContent>>(queryPlan.SortContent);

                RepaireGroup(filterGroup, dataQuery, out bool delFlag);
                colContent.RemoveAll(col => dataQuery.DataQueryColumns.All(dqCol => dqCol.ID != col.ID));
                sortContent.RemoveAll(col => dataQuery.DataQueryColumns.All(dqCol => dqCol.ID != col.ID));

                queryPlan.FilterContent = JsonConvert.SerializeObject(filterGroup);
                queryPlan.ColumnContent = JsonConvert.SerializeObject(colContent);
                queryPlan.SortContent = JsonConvert.SerializeObject(sortContent);
                return queryPlan;
            }
            catch (Exception e)
            {
                throw new Exception(string.Format(CommonStringClassService.DataQueryService_RepairQueryPlan1,dqId,e.Message), e);
            }
        }

        /// <summary>
        /// 修复查询方案的group
        /// </summary>
        /// <param name="group"></param>
        /// <param name="dataQuery"></param>
        /// <param name="isNeedDel">是否需要删除当前group，true:需要删除，false:不需删除</param>
        /// <returns></returns>
        private void RepaireGroup(Group group, DataQuery dataQuery, out bool isNeedDel)
        {
            isNeedDel = false;
            if (group.Filters != null && group.Filters.Count > 0)
            {
                int cnt = group.Filters.Count;
                List<int> removeIndex = new List<int>();
                for (int i = 0; i < cnt; i++)
                {
                    var ele = group.Filters[i];
                    if (ele is Filter filter)
                    {
                        //如果filter无效，处理掉当前索引
                        if (!IsValidField(filter, dataQuery))
                        {
                            HandleIndex(cnt, removeIndex, i);
                        }
                    }
                    else if (ele is Group grp)
                    {
                        RepaireGroup(grp, dataQuery, out bool delFlag);
                        if (delFlag)
                        {
                            HandleIndex(cnt, removeIndex, i);
                        }
                    }
                }
                if (removeIndex.Count > 0)
                {
                    removeIndex.ForEach(i => group.Filters[i] = null);
                    group.Filters.RemoveAll(f => f == null);
                }
                //如果处理完毕后该filter集合为空，删掉该group
                if (group.Filters.Count == 0)
                {
                    isNeedDel = true;
                }
            }
        }

        private void HandleIndex(int cnt, List<int> removeIndex, int i)
        {
            //如果只有1个filter直接删除
            if (cnt == 1)
            {
                removeIndex.Add(i);
            }
            else //如果cnt > 1 
            {
                //如果是开头元素，删掉后方的relation
                if (i == 0)
                {
                    removeIndex.Add(i);
                    removeIndex.Add(i + 1);
                }
                //如果是开头元素，删掉前方的relation
                else if (i == cnt - 1)
                {
                    removeIndex.Add(i - 1);
                    removeIndex.Add(i);
                }
                //如果在中间，默认删除前面的relation，否则尝试删除后方
                else
                {
                    if (!removeIndex.Contains(i - 1))
                    {
                        removeIndex.Add(i - 1);
                    }
                    else if(!removeIndex.Contains(i + 1))
                    {
                        removeIndex.Add(i + 1);
                    }
                    removeIndex.Add(i);
                }
            }
        }

        /// <summary>
        /// filter.Code是否有效
        /// </summary>
        /// <param name="filter"></param>
        /// <param name="dataQuery"></param>
        /// <returns>true:有效 </returns>
        private bool IsValidField(Filter filter, DataQuery dataQuery)
        {
            var arr = filter.Code.Split('.');
            var sourceAlias = arr[0];
            var columnName = arr[1];
            var source = dataQuery.DataQuerySources.FirstOrDefault(s => s.Alias == sourceAlias);
            var columns = dataQuery.DataQueryColumns.Where(col => col.DataQuerySourceID == source.ID).ToList();
            var flag = columns.All(col => col.Name != columnName);
            if (flag)
            {
                var dataObject = source.DataObject;
                flag = dataObject.Columns.All(col => col.ColumnName != columnName);
            }
            return !flag;
        }

        public class QueryPlanColumnContent
        {
            public string ID { get; set; }
        }
        public class QueryPlanSortContent
        {
            public string ID { get; set; }
            public int SortType { get; set; }
        }
    }
}
